﻿using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using Mido.Domain;
using Mido.UiModules.SettingsModule;
using System;
using System.Globalization;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Pen = System.Windows.Media.Pen;
using Point = System.Windows.Point;

namespace Mido.Utils.Watermark
{
    internal static class WatermarkHelper
    {
		// test
	
        internal static Rect OnRender(ProcessedImage processedImage, DrawingContext dc)
        {
            if (processedImage == null)
                throw new ArgumentNullException("processedImage");
            if (dc == null)
                throw new ArgumentNullException("dc");

            dc.PushOpacity(processedImage.Settings.Opacity / 100D);

            bool hasImage = processedImage.Settings.ContentType != ContentType.OnlyText && !string.IsNullOrEmpty(processedImage.Settings.ImagePath) && File.Exists(processedImage.Settings.ImagePath);
            bool hasText = processedImage.Settings.ContentType != ContentType.OnlyImage && !string.IsNullOrEmpty(processedImage.Settings.Text);

            double imageWidth = 0;
            double imageHeight = 0;

            BitmapImage image = null;
            if (hasImage)
            {
                image = new BitmapImage(new Uri(processedImage.Settings.ImagePath));

				if (processedImage.Settings.ImageSizeType == FontSizeType.Percents)
				{
					imageHeight = processedImage.FullImage.PixelHeight*processedImage.Settings.RelativeImageSize/100D;
					imageWidth = image.PixelWidth*imageHeight/image.PixelHeight;
				}
				else
				{
					imageHeight = processedImage.Settings.RelativeImageSize;
					imageWidth = image.PixelWidth * imageHeight / image.PixelHeight;
				}
            }

            double textWidth = 0;
            double textHeight = 0;

            FormattedText formattedText = null;
            if (hasText)
            {
                Typeface typeface = new Typeface(processedImage.Settings.FontName);
                SolidColorBrush brush = new SolidColorBrush(processedImage.Settings.Color);
				// special check for case when user add small image
	            int percentSize = processedImage.FullImage.PixelHeight*processedImage.Settings.FontSize/100;
	            if (percentSize <= 0)
		            percentSize = 1;
				int fontSize = processedImage.Settings.FontSizeType == FontSizeType.Pixels ? processedImage.Settings.FontSize : percentSize;

                formattedText = new FormattedText(processedImage.Settings.Text, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, typeface, fontSize, brush);
                
                if (processedImage.Settings.IsUnderline)
                    formattedText.SetTextDecorations(TextDecorations.Underline);
                if (processedImage.Settings.IsItalic) 
                    formattedText.SetFontStyle(FontStyles.Italic);
                if (processedImage.Settings.IsBold) 
                    formattedText.SetFontWeight(FontWeights.Bold);
                
                textWidth = formattedText.Width;
                textHeight = formattedText.Height;

                formattedText.TextAlignment = processedImage.Settings.TextAlignment;
            }

            double x = 0, y = 0, width = hasImage && hasText ? imageWidth + textWidth + 10 : imageWidth + textWidth, height = Math.Max(imageHeight, textHeight);

            if (processedImage.CustomPosition.HasValue)
                x = processedImage.CustomPosition.Value.X;
            else if (processedImage.Settings.Side == WatermarkSide.LeftTop || processedImage.Settings.Side == WatermarkSide.LeftCenter || processedImage.Settings.Side == WatermarkSide.LeftBottom)
                x = 10;
            else if (processedImage.Settings.Side == WatermarkSide.CenterTop || processedImage.Settings.Side == WatermarkSide.CenterCenter || processedImage.Settings.Side == WatermarkSide.CenterBottom)
                x = processedImage.FullImage.PixelWidth / 2D - width / 2;
            else if (processedImage.Settings.Side == WatermarkSide.RightTop || processedImage.Settings.Side == WatermarkSide.RightCenter || processedImage.Settings.Side == WatermarkSide.RightBottom)
                x = processedImage.FullImage.PixelWidth - 10 - width;


            if (processedImage.CustomPosition.HasValue)
                y = processedImage.CustomPosition.Value.Y;
            else if (processedImage.Settings.Side == WatermarkSide.LeftTop || processedImage.Settings.Side == WatermarkSide.CenterTop || processedImage.Settings.Side == WatermarkSide.RightTop)
                y = 10;
            else if (processedImage.Settings.Side == WatermarkSide.LeftCenter || processedImage.Settings.Side == WatermarkSide.CenterCenter || processedImage.Settings.Side == WatermarkSide.RightCenter)
                y = processedImage.FullImage.PixelHeight / 2D - height / 2;
            else if (processedImage.Settings.Side == WatermarkSide.LeftBottom || processedImage.Settings.Side == WatermarkSide.CenterBottom || processedImage.Settings.Side == WatermarkSide.RightBottom)
                y = processedImage.FullImage.PixelHeight - 10 - height;


			// for rotation
			if (processedImage.CustomPosition.HasValue)
			{}
			else if (processedImage.Settings.WatermarkAngle == WatermarkAngle.a180)
			{
				x += width;
				y += height;
			}
			else if (processedImage.Settings.WatermarkAngle == WatermarkAngle.a90)
			{
				if (processedImage.Settings.Side == WatermarkSide.LeftTop ||
					processedImage.Settings.Side == WatermarkSide.LeftCenter)
				{
					x += height;
				}
				else if (processedImage.Settings.Side == WatermarkSide.LeftBottom)
				{
					x += height;
					y += - width + height;
				}
				else if (processedImage.Settings.Side == WatermarkSide.CenterTop ||
					processedImage.Settings.Side == WatermarkSide.CenterCenter)
				{
					x += height;
				}
				else if (processedImage.Settings.Side == WatermarkSide.CenterBottom)
				{
					x += height;
					y += - width + height;
				}
				else if (processedImage.Settings.Side == WatermarkSide.RightTop ||
					processedImage.Settings.Side == WatermarkSide.RightCenter)
				{
					x += width;
				}
				else if (processedImage.Settings.Side == WatermarkSide.RightBottom)
				{
					x += width;
					y += - width + height;
				}
			}
			else if (processedImage.Settings.WatermarkAngle == WatermarkAngle.a270)
			{
				if (processedImage.Settings.Side == WatermarkSide.LeftTop ||
					processedImage.Settings.Side == WatermarkSide.LeftCenter)
				{
					y += width;
				}
				else if (processedImage.Settings.Side == WatermarkSide.LeftBottom)
				{
					y += height;
				}
				else if (processedImage.Settings.Side == WatermarkSide.CenterTop ||
					processedImage.Settings.Side == WatermarkSide.CenterCenter)
				{
					y += width;
				}
				else if (processedImage.Settings.Side == WatermarkSide.CenterBottom)
				{
					y += height;
				}
				else if (processedImage.Settings.Side == WatermarkSide.RightTop ||
					processedImage.Settings.Side == WatermarkSide.RightCenter)
				{
					y += width;
					x += width - height;
				}
				else if (processedImage.Settings.Side == WatermarkSide.RightBottom)
				{
					x += width - height;
					y += height;
				}
			}

			dc.PushTransform(new TranslateTransform(x, y));
            dc.PushTransform(new RotateTransform(
                processedImage.Settings.WatermarkAngle == WatermarkAngle.a0 ? 0 :
                processedImage.Settings.WatermarkAngle == WatermarkAngle.a90 ? 90 :
                processedImage.Settings.WatermarkAngle == WatermarkAngle.a180 ? 180 :
                processedImage.Settings.WatermarkAngle == WatermarkAngle.a270 ? 270 : 0));


            if (processedImage.Settings.ContentType == ContentType.OnlyImage)
            {
                if (hasImage)
                    dc.DrawImage(image, new Rect(0, 0, imageWidth, imageHeight));
            }
            else if (processedImage.Settings.ContentType == ContentType.OnlyText)
            {
                if (hasText)
                {
                    double textY = height / 2D - textHeight / 2D;
                    double textX =
                        formattedText.TextAlignment == TextAlignment.Center ? width - textWidth / 2D :
                        formattedText.TextAlignment == TextAlignment.Right ? width : width - textWidth;


                    Geometry g = formattedText.BuildGeometry(new Point(textX, textY));
                    dc.DrawGeometry(new SolidColorBrush(processedImage.Settings.Color), new Pen(new SolidColorBrush(processedImage.Settings.Stroke), processedImage.Settings.StrokeWidth), g);
                }
            }
            else if (processedImage.Settings.ContentType == ContentType.ImageBeforeText)
            {
                if (hasImage)
                {
                    double imageY = height/2D - imageHeight/2D;
                    dc.DrawImage(image, new Rect(0, imageY, imageWidth, imageHeight));
                }

                if (hasText)
                {
                    double textY = height / 2D - textHeight/2D;
                    double textX =
                        formattedText.TextAlignment == TextAlignment.Center ? width - textWidth / 2D :
                        formattedText.TextAlignment == TextAlignment.Right ? width : width - textWidth;


                    Geometry g = formattedText.BuildGeometry(new Point(textX, textY));
                    dc.DrawGeometry(new SolidColorBrush(processedImage.Settings.Color), new Pen(new SolidColorBrush(processedImage.Settings.Stroke), processedImage.Settings.StrokeWidth), g);
                }
            }
            else if (processedImage.Settings.ContentType == ContentType.TextBeforeImage)
            {
                if (hasText)
                {
                    double textY = height / 2D - textHeight/2D;
                    double textX =
                        formattedText.TextAlignment == TextAlignment.Center ? textWidth / 2D :
                        formattedText.TextAlignment == TextAlignment.Right ? textWidth : 0;

                    Geometry g = formattedText.BuildGeometry(new Point(textX, textY));
                    dc.DrawGeometry(new SolidColorBrush(processedImage.Settings.Color), new Pen(new SolidColorBrush(processedImage.Settings.Stroke), processedImage.Settings.StrokeWidth), g);
                }
                
                if (hasImage)
                {
                    double imageY = height / 2D - imageHeight/2D;
                    dc.DrawImage(image, new Rect(width - imageWidth, imageY, imageWidth, imageHeight));
                }
            }

			if (processedImage.Settings.WatermarkAngle == WatermarkAngle.a0)
				return new Rect(x, y, width, height);
			if (processedImage.Settings.WatermarkAngle == WatermarkAngle.a90)
				return new Rect(x - height, y, height, width);
			if (processedImage.Settings.WatermarkAngle == WatermarkAngle.a180)
				return new Rect(x - width, y - height, width, height);
			if (processedImage.Settings.WatermarkAngle == WatermarkAngle.a270)
				return new Rect(x, y - width, height, width);

			throw new InvalidOperationException();
        }

        internal static BitmapSource CreateImage(byte[] imageData, WatermarkAngle rotateAngle, int width, int height)
        {
            if (imageData == null)
                return null;

            BitmapImage result = new BitmapImage();
            result.BeginInit();

            bool needInvert = rotateAngle == WatermarkAngle.a90 || rotateAngle == WatermarkAngle.a270;

            result.DecodePixelWidth = needInvert ? height : width;
            result.DecodePixelHeight = needInvert ? width : height;

            result.StreamSource = new MemoryStream(imageData);
            result.CreateOptions = BitmapCreateOptions.None;
            result.CacheOption = BitmapCacheOption.Default;
            result.EndInit();
			result.Freeze();

            double angle =
                rotateAngle == WatermarkAngle.a90 ? 90 :
                rotateAngle == WatermarkAngle.a180 ? 180 :
                rotateAngle == WatermarkAngle.a270 ? 270 : 0;

            TransformedBitmap bitmap = new TransformedBitmap(result, new RotateTransform(angle, 0.5, 0.5));
			bitmap.Freeze();

	        return bitmap;
        }

        internal static System.Drawing.Size GetImageSize(string filePath)
        {
            if (string.IsNullOrEmpty(filePath)) 
                throw new ArgumentNullException("filePath");
            if (!File.Exists(filePath))
                throw new ArgumentException("The following file doesn't exist.", "filePath");

            BitmapDecoder decoder = BitmapDecoder.Create(new Uri(filePath), BitmapCreateOptions.None, BitmapCacheOption.None);
            BitmapFrame frame = decoder.Frames[0];

            return new System.Drawing.Size(frame.PixelWidth, frame.PixelHeight);
        }

        internal static System.Drawing.Size CalculateNewSize(System.Drawing.Size currentSize, SettingsModel settings)
        {
            if (settings == null) 
                throw new ArgumentNullException("settings");
            if (currentSize.IsEmpty)
                throw new ArgumentException("Current size cannot be empty.", "currentSize");
            if (settings.MaxWidth <= 0)
                throw new ArgumentException("maxWidth cannot be less zero.", "settings");
            if (settings.MaxHeight <= 0)
                throw new ArgumentException("maxHeight cannot be less zero.", "settings");

            int originalHeight = Convert.ToInt32(currentSize.Height);
            int originalWidth = Convert.ToInt32(currentSize.Width);

            float sizeIndex = Math.Max(originalHeight / Convert.ToSingle(settings.MaxHeight), originalWidth / Convert.ToSingle(settings.MaxWidth));
            sizeIndex = Math.Max(sizeIndex, 1);

            int height = Convert.ToInt32(originalHeight / sizeIndex);
            int width = Convert.ToInt32(originalWidth / sizeIndex);

            return new System.Drawing.Size(width, height);
        }

		internal static void SaveWatermarkedImageTo(DrawingImage bitmapImage, string outputPath, ImageFormat format)
        {
            if (bitmapImage == null)
                throw new ArgumentNullException("bitmapImage");
            if (string.IsNullOrEmpty(outputPath))
                throw new ArgumentNullException("outputPath");
            
            int height = Convert.ToInt32(bitmapImage.Height);
            int width = Convert.ToInt32(bitmapImage.Width);
            
            DrawingVisual drawingVisual = new DrawingVisual();
            DrawingContext context = drawingVisual.RenderOpen();
            context.DrawImage(bitmapImage, new Rect(0, 0, width, height));
            context.Close();

            // The BitmapSource that is rendered with a Visual.
            RenderTargetBitmap rtb = new RenderTargetBitmap(width, height, 96d, 96d, PixelFormats.Default);
            rtb.Render(drawingVisual);

            // Encoding the RenderBitmapTarget as a PNG file.
			BitmapEncoder tiff = null;
			if (format == ImageFormat.Jpeg)
				tiff= new JpegBitmapEncoder();

			if (format == ImageFormat.Bmp)
				tiff = new BmpBitmapEncoder();

			if (format == ImageFormat.Png)
				tiff = new PngBitmapEncoder();

			if (format == ImageFormat.Gif)
				tiff = new GifBitmapEncoder();

			if (tiff != null)
			{
				tiff.Frames.Add(BitmapFrame.Create(rtb));

				using (Stream stm = File.Create(outputPath))
					tiff.Save(stm);
			}
        }

	    public static BitmapImage CreateThumbnailImage(string imageUri, int width, int height)
	    {
			Image tempImage = Image.FromFile(imageUri);

			int dw = tempImage.Width;
			int dh = tempImage.Height;
			int tw = width;
			int th = height;
			double zw = (tw / (double)dw);
			double zh = (th / (double)dh);
			double z = (zw <= zh) ? zw : zh;
			dw = (int)(dw * z);
			dh = (int)(dh * z);

			Image image = new Bitmap(dw, dh);
			Graphics g = Graphics.FromImage(image);
			g.InterpolationMode = InterpolationMode.HighQualityBicubic;
			g.DrawImage(tempImage, 0, 0, dw, dh);
			g.Dispose();

			tempImage.Dispose();

			MemoryStream ms = new MemoryStream();

			image.Save(ms, ImageFormat.Bmp);

			BitmapImage bi = new BitmapImage();
			bi.BeginInit();
			bi.StreamSource = ms;
			bi.EndInit();
			bi.Freeze();
			image.Dispose();
		    return bi;
	    }
    }
}
